package main;

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.*;
import java.awt.image.BufferedImage;

import javax.swing.JPanel;
import javax.swing.SwingUtilities;

//Nikolas Wolfe
//3/18/09
//CIS 4930
//Game Of Life

//This maintains the grid upon which the Game Of Life occurs

public class PaneOfLife extends JPanel
{
	static private final int WHITE 	= 0xFFFFFFFF;
	static private final int RED 	= 0xFFFF0000; 
	static private final int GREEN 	= 0xFF00FF00;
	static private final int BLUE 	= 0xFF0000FF;
	
	private final int squareSize = 4;			 // one side of a drawn circle
	private final int WIDTH = 200;				 // 800 pixel wide canvas
	private final int HEIGHT = 200;				 // 800 pixel high canvas
	private ToroidalArray imageArray;			 // array of colors on screen
	private BufferedImage image;				 // screen image to refresh
	private Graphics2D g2d;						 // Java AWT Graphics object
	private MouseListener mouseListener;		 // event handler for mouse
	private MouseMotionListener motionListener;	 // mouse motion event handler
	private boolean paused = false;				 // state variable
	
	public PaneOfLife()
	{
		this.imageArray = new ToroidalArray( WIDTH, HEIGHT );
		
		Dimension dim = new Dimension( WIDTH, WIDTH );
		this.setPreferredSize( dim );
		image = new BufferedImage( WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB );
		
		g2d = image.createGraphics();
		g2d.setColor( Color.WHITE );
		g2d.fillRect( 0, 0, WIDTH, WIDTH );
	}
	
	//=========================================================================
	// experimental()
	
	public void updateGrid( final ToroidalArray array )
	{
		new Thread( new Runnable() 
		{
			public void run()
			{
				final int xMax = WIDTH;
				final int yMax = HEIGHT;
				SwingUtilities.invokeLater( new Runnable()
				{
					public void run()
					{
						for(int i = 0; i < xMax; ++i)
						{
							for(int j = 0; j < yMax; ++j)
							{
								int color = array.get(i,j);
								drawSquare( new Point(i,j), 
										new Color(color) );
							}
						}
					}
				});
			}
		}).start();
	}
	
	//=========================================================================
	// initialize()
	
	public void initialize()
	{
		// clear the array
		for( int i = 0; i < imageArray.getXMax(); ++i )
		{
			for( int j = 0; j < imageArray.getYMax(); ++j )
			{
				imageArray.set(i, j, WHITE);
			}
		}
		createListeners();
		registerListeners();
	}
	
	//=========================================================================
	// paintComponent()
	
	public void paintComponent( Graphics g )
	{
		super.paintComponent( g );
		g.drawImage( image, 0, 0, null );
	}
		
	//=========================================================================
	// isARGBColor()
	
	private boolean isARGBColor( Point point, int argb )
	{
		int x = point.x;
		int y = point.y;
		int RGB = image.getRGB(x, y);
		return( RGB == argb );
	}
	
	//=========================================================================
	// drawSquare() -- draws a 2x2 square on the grid
	
	private void drawSquare( Point point, Color color )
	{
		int x = point.x*4;
		int y = point.x*4;
		
		g2d.setColor( color );
		g2d.fillRect( x, y, squareSize, squareSize);
		repaint();
	}
	
	//=========================================================================
	// createListeners()
	
	private void createListeners()
	{
		mouseListener = new MouseAdapter()
		{
			public void mousePressed( MouseEvent event )
			{
				// set current square
				Point point = event.getPoint();
				if( !isARGBColor( point, GREEN )){
					//drawSquare( point, new Color(GREEN) );
					imageArray.set(point.x, point.y, GREEN);
					updateGrid(imageArray);
				}
				else {
					drawSquare( point, new Color(WHITE) );
					imageArray.set(point.x, point.y, WHITE);
				}
			}
			public void mouseClicked( MouseEvent event ){ /*nuffin*/ } 
		};
		motionListener = new MouseMotionListener()
		{
			public void mouseMoved( MouseEvent event )
			{
				Point point = event.getPoint();
				if( isARGBColor( point, GREEN )) {
					setCursor( Cursor.getPredefinedCursor( Cursor.CROSSHAIR_CURSOR ));
				}
				else {
					setCursor( Cursor.getDefaultCursor() );
				}
			}
			public void mouseDragged( MouseEvent event ){ /*nuffin*/ }
		};
	}
	
	//=========================================================================
	// registerListeners()
	
	private void registerListeners()
	{
		// ensures that this is not called before createListeners()
		if( mouseListener == null )
			throw new IllegalStateException("MouseListeners not initialized!");
		addMouseListener( mouseListener );
		addMouseMotionListener( motionListener );
	}
	
	//=========================================================================
	// unregisterListeners()
	
	private void unregisterListeners()
	{
		if( mouseListener == null )
			throw new IllegalStateException(
					"MousePanel.unregisterListeners(): not initialized()" );
		removeMouseListener( mouseListener );
		removeMouseMotionListener( motionListener );
	}

	//=========================================================================
	// pause() -- pauses the grid from listening for mouse movement
	
	public void pausePane()
	{
		if( !paused )
		{
			unregisterListeners();
			paused = true;
		}
	}
	
	//=========================================================================
	// pause() -- resumes the grid for listening for mouse movement
	
	public void resumePane()
	{
		if( paused )
		{
			registerListeners();
			paused = false;
		}
	}
	
	//=========================================================================
	// getWidth(), getHeight(), getImageArray(), getSquaresize()
	
	public int getWidth()
	{
		return WIDTH;
	}

	public int getHeight()
	{
		return HEIGHT;
	}

	public ToroidalArray getImageArray()
	{
		return imageArray;
	}
	
	public int getSquareSize()
	{
		return squareSize;
	}
}
